#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <unistd.h>
#include <wait.h>
#include <cstring>
#include <iostream>
#define PATH "/home/yyf/linux_code/24.7.14/test.cc"
#define SIZE 4096
enum
{
    ShmgetErr = 1,
    ShmatErr,
    ShmdtErr,
    ShmctlErr,
    CreatePipeError,
    WritePipeError,
    ReadPipeError,
    WaitError
};
class Fifo
{
public:
    Fifo()
    {
        int pipefd[2];
        int n = pipe(pipefd);
        if (n == -1)
        {
            std::cerr << "Create Pipe Error!" << "reason:" << strerror(errno) << std::endl;
            exit(CreatePipeError);
        }
        _wfd = pipefd[1];
        _rfd = pipefd[0];
    }
    void Write()
    {
        close(_rfd);
        char c = 'A';
        ssize_t n = write(_wfd, &c, 1);
        if (n == -1)
        {
            std::cerr << "Write Pipe Error!" << "reason:" << strerror(errno) << std::endl;
            exit(WritePipeError);
        }
    }
    bool Read()
    {
        close(_wfd);
        char c;
        bool ret = true;
        ssize_t n = read(_rfd, &c, 1);
        if(n < 0)
        {
            std::cerr << "Read Pipe Error!" << strerror(errno) << std::endl;
            exit(ReadPipeError);
            ret = false;
        }
        else if(n == 0)
        {
            ret = false;
        }
        
        return ret;

    }

protected:
    int _wfd;
    int _rfd;
};

class Shm
{
public:
    Shm()
    {
        // 第一步：创建/获取共享内存
        int tempShmid = shmget(ftok(PATH, 1), SIZE, IPC_CREAT | 0666);
        if (tempShmid == -1)
        {
            std::cerr << "Create Shm Error!" << "reason:" << strerror(errno) << std::endl;
            exit(ShmgetErr);
        }
        _shmid = tempShmid;
        // 第二步：关联
        void *tempAddr = shmat(_shmid, nullptr, 0);
        if ((uint64_t)tempAddr == -1)
        {
            printf("%d\n", _shmid);
            std::cerr << "Attach Shm Error!" << "reason:" << strerror(errno) << std::endl;
            exit(ShmatErr);
        }
        _addr = tempAddr;
    }
    ~Shm()
    {
        // 去关联
        int n = shmdt(_addr);
        if (n == -1)
        {
            std::cerr << "Detach Shm Error!" << "reason:" << strerror(errno) << std::endl;
            exit(ShmdtErr);
        }
        // 释放共享内存
        n = shmctl(_shmid, IPC_RMID, nullptr);
        if (n == -1)
        {
            std::cerr << "Delete Shm Error!" << std::endl;
            exit(ShmctlErr);
        }
    }
    void *GetAddr()
    {
        return _addr;
    }
    int GetShmid()
    {
        return _shmid;
    }

protected:
    int _shmid;
    void *_addr;
};

int main()
{
    // 子进程读共享内存中的数据，父进程数据写入共享内存
    Fifo fifo;
    pid_t id = fork();
    if (id == 0)
    {
        // child
        Shm sh;
        while (true)
        {
            if(!fifo.Read())break;
            char *addr = (char *)sh.GetAddr();
            std::cout << "Shm content:" << addr << std::endl;
        }
        exit(0);
    }
    // father
    Shm sh;
    while (true)
    {
        char *buffer = (char *)sh.GetAddr();
        int cnt = 5;
        while (cnt--)
        {
            snprintf(buffer, 64, "Hello,Child,My pid:%d,My cnt:%d", getpid(), cnt);
            fifo.Write();
            sleep(1);
        }
    }
    // 等待子进程
    id = waitpid(id,nullptr,0);
    if(id == -1)
    {
        std::cerr << "wait sub process error!" << "reason:" << strerror(errno) << std::endl;
        exit(WaitError);
    }
    return 0;
}